#!/usr/bin/perl -w

=head1 NAME

whazzup - Display today's google calendar

=head1 DESCRIPTION

Reads any online ICS file, parses it, and generates a brief overview of
today's upcoming schedule.

=head1 SYNOPSIS

  whazzup

=head1 DEPENDENCIES

L<iCal::Parser>, L<Time::Format>, L<Date::Manip>, L<LWP::Simple>

=cut

use strict;
use iCal::Parser;
use Time::Format qw(%time %strftime %manip);

=head1 VARIABLES

=over 4

=item * $url - points to the online ics file to fetch.
=item * $cachetime - how many seconds to wait before fetching again
=item * $icsfile - where to store the ics file.

=back

=cut

my $url =
  'http://www.google.com/calendar/ical/cmauch@gmail.com/public/basic.ics';
my $cachetime = 1800;
my $icsfile   = '/home/cpm/.icalendar';

if ( &GetFileTime > $cachetime ) {
    use LWP::Simple;
    print "Calendar file is older than 30 mins, grabbing a new copy\n";

    my $icsdata = get $url or die "Couldn't get $url, yukky!";

    open( ICAL, ">$icsfile" );
    print ICAL $icsdata;
    close ICAL;

} ## end if ( &GetFileTime > $cachetime)

my $parser = iCal::Parser->new();
my $hash   = $parser->parse( $icsfile );
my %hashorama;

print "Google Calendar Says ... This is whazzup for TODAY

Today being $time{ 'Weekday, the ddth of Month, in the yyyyth year' } of our
Lord and Savior, the Flying Spaghetti Monster.\n\n";

while ( my ( $source, $value ) = each %{ $hash } ) {
    if ( $source =~ /^events/ ) {
        while ( my ( $year, $year_ref ) = each %{ $value } ) {
            while ( my ( $month, $month_ref ) = each %{ $year_ref } ) {
                while ( my ( $day, $day_ref ) = each %{ $month_ref } ) {
                    while ( my ( $items, $items_ref ) = each %{ $day_ref } ) {
                        if (     ( $year eq $time{ 'yyyy' } )
                             and ( $month eq $time{ 'm{on}' } )
                             and ( $day   eq $time{ 'd' } ) )
                        {
                            $hashorama{ $manip{ '%s', $items_ref->{ 'DTSTART' } } } = 
                              &event_handler( $items_ref->{ 'SUMMARY' },
                                              $items_ref->{ 'DESCRIPTION' },
                                              $items_ref->{ 'LOCATION' },
                                              $items_ref->{ 'CLASS' },
                                              $items_ref->{ 'hours' },
                                              $items_ref->{ 'LAST-MODIFIED' },
                                              $items_ref->{ 'STATUS' },
                                              $items_ref->{ 'DTSTAMP' },
                                              $items_ref->{ 'DTSTART' },
                                              $items_ref->{ 'DTEND' },
                                              $items_ref->{ 'CREATED' },
                                              $items_ref->{ 'ORGANIZER' }
                                            );
                        } ## end if ( ( $year eq $time{...
                    } ## end while ( my ( $items, $items_ref...
                } ## end while ( my ( $day, $day_ref...
            } ## end while ( my ( $month, $month_ref...
        } ## end while ( my ( $year, $year_ref...
    } ## end if ( $source =~ /^events/)
} ## end while ( my ( $source, $value...

for my $keys ( sort keys %hashorama ) { # For sorting
    print $hashorama{ $keys };
}

=head1 FUNCTIONS

=over 4

=item * event_handler

Basic event output generation, accepts quite a few strings, and notably,
a reference to the page creator.  It then mucks around with the text to
make it more human readable, and returns it's data as a big-fat string.

=cut

sub event_handler {
    my ( $summary, $description, $location, $class,
         $hours,   $modded,      $status,   $stamp,
         $start,   $end,         $created,  $organizer
       ) = @_;

    my ( @result, $startformat, $endformat );

    my $startepoch = $manip{ '%s', $start };
    my $endepoch   = $manip{ '%s', $end };

    $summary     =~ s/\\//g if $summary;
    $location    =~ s/\\//g if $location;
    $description =~ s/\\//g if $description;

    push( @result, "You have a " );
    push( @result, $status ) if $status;
    push( @result, " appointment " );
    push( @result, &DateMuckery( $startepoch, $endepoch ) );

    push( @result, "* Location     : " . $location . "\n" ) if $location;
    push( @result, "* Summary      : " . $summary . " \n" ) if $summary;
    push( @result, "* Details      : " . $description . "\n" )
      if $description;

    for my $source ( keys %{ $organizer } ) {
        if ( $source =~ /^CN/ ) {
            push( @result, "* Organized by : $organizer->{$source}" );
        } else {
            my $email = $organizer->{ $source };
            $email =~ s/MAILTO://g;
            push( @result, " <$email>\n" );
        }
    } ## end for my $source ( keys %...

    push( @result, "\n" );
  return join( '', @result );
} ## end sub event_handler

=item * DataMuckery

Performs a few tests in order to determine when the event took place in
relation to $now, and outputs an appropriate result.

=cut

sub DateMuckery {
    my ( $start, $end ) = @_;
    my $result;
    my $now         = time;
    my $startformat = $time{ 'H:mm am', $start };
    my $endformat   = $time{ 'H:mm am', $end };

    if ( ( $start > $now ) and ( $end > $now ) ) {
        $result =
          "that is scheduled to happen\n* Starts       : $startformat, that is in "
          . &TimeLeft( $start )
          . ".\n* Ends         : $endformat, that is in "
          . &TimeLeft( $end ) . ".\n";
    }

    if ( ( $start < $now ) and ( $end < $now ) ) {
        $result =
          "that has allready happened\n* Started      : $startformat, that was "
          . &TimeLeft( $start )
          . " ago.\n* Ended        : $endformat, that was "
          . &TimeLeft( $end )
          . " ago.\n";
    } ## end if ( ( $start < $now )...

    if ( ( $start < $now ) and ( $end > $now ) ) {
        $result =
            "that IS HAPPENING NOW!\n* Started      : "
          . &TimeLeft( $start )
          . ".\n* Ends in      : "
          . &TimeLeft( $end ) . ".\n";
    }

  return $result;

} ## end sub DateMuckery

=item * GetFileTime

Simple function which returns a file's last modified timestamp.

=cut

sub GetFileTime {
    my ( $dev,  $ino,   $mode,  $nlink, $uid,     $gid, $rdev,
         $size, $atime, $mtime, $ctime, $blksize, $blocks
       ) = stat( $icsfile );
    my $diff = time - $mtime;
  return $diff;
}

=item * TimeLeft

A lengthy function which displays two blurbs to text.  I use this
function in quite a few other scripts.  Maybe it should be a module.

=cut

sub TimeLeft {
    my $comparetime = $_[0];
    my $epochtime   = time;

    my ( $temp, $yearsince, $remainder, $since, @datestring, @alldone );

    my $datecount = 0;
    my $depth     = 2;

    if ( $epochtime gt $comparetime ) {
        $since = $epochtime - $comparetime;
    } else {
        $since = $comparetime - $epochtime;
    }

    my $year  = 60 * 60 * 24 * 365;
    my $month = 60 * 60 * 24 * 30;
    my $week  = 60 * 60 * 24 * 7;
    my $day   = 60 * 60 * 24;
    my $hour  = 60 * 60;
    my $min   = 60;

    my $years = sprintf( "%.1d", $since / $year );
    $remainder = $since - ( $years * $year );

    if ( ( $years ne 0 ) && ( $datecount < $depth ) ) {
        if ( $years eq 1 ) {
            push( @datestring, "$years year" );
        } else {
            push( @datestring, "$years years" );
        }
        $datecount++;
    } ## end if ( ( $years ne 0 ) &&...
    my $months = sprintf( "%.1d", $remainder / $month );
    $remainder = $remainder - ( $months * $month );

    if ( ( $months ne 0 ) && ( $datecount < $depth ) ) {
        if ( $months eq 1 ) {
            push( @datestring, "$months month" );
        } else {
            push( @datestring, "$months months" );
        }
        $datecount++;
    } ## end if ( ( $months ne 0 ) ...

    my $weeks = sprintf( "%.1d", $remainder / $week );
    $remainder = $remainder - ( $weeks * $week );

    if ( ( $weeks ne 0 ) && ( $datecount < $depth ) ) {
        if ( $weeks eq 1 ) {
            push( @datestring, "$weeks week" );
        } else {
            push( @datestring, "$weeks weeks" );
        }
        $datecount++;
    } ## end if ( ( $weeks ne 0 ) &&...

    my $days = sprintf( "%.1d", $remainder / $day );
    $remainder = $remainder - ( $days * $day );

    if ( ( $days ne 0 ) && ( $datecount < $depth ) ) {
        if ( $days eq 1 ) {
            push( @datestring, "$days day" );
        } else {
            push( @datestring, "$days days" );
        }
        $datecount++;
    } ## end if ( ( $days ne 0 ) &&...

    my $hours = sprintf( "%.1d", $remainder / $hour );
    $remainder = $remainder - ( $hours * $hour );
    if ( ( $hours ne 0 ) && ( $datecount < $depth ) ) {
        if ( $hours eq 1 ) {
            push( @datestring, "$hours hour" );
        } else {
            push( @datestring, "$hours hours" );
        }
        $datecount++;
    } ## end if ( ( $hours ne 0 ) &&...

    my $mins = sprintf( "%.1d", $remainder / $min );
    $remainder = $remainder - ( $mins * $min );

    if ( ( $mins ne 0 ) && ( $datecount < $depth ) ) {
        if ( $mins eq 1 ) {
            push( @datestring, "$mins minute" );
        } else {
            push( @datestring, "$mins minutes" );
        }
        $datecount++;
    } ## end if ( ( $mins ne 0 ) &&...

    if ( ( $remainder ne 0 ) && ( $datecount < $depth ) ) {
        if ( $remainder eq 1 ) {
            push( @datestring, "$remainder second" );
        } else {
            push( @datestring, "$remainder seconds" );
        }
        $datecount++;
    } ## end if ( ( $remainder ne 0...

    $temp = pop( @datestring );
    foreach my $date ( @datestring ) {
        push( @alldone, $date . ", " );
    }
    push( @alldone, $temp );

  return join( '', @alldone );

    #print @alldone;
} ## end sub TimeLeft

=back

=head1 AUTHOR

Charles Mauch <cmauch@gmail.com>

=head1 LICENSE

Copyright (c) 2006 Charles Mauch

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.  See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
Street, Fifth Floor, Boston, MA  02110-1301, USA.

=head1 SEE ALSO

perl(1).

=cut

# $Id: whazzup 37 2006-09-30 04:09:44Z cmauch $
